package com.ahmedmisbah.andgenplus.utils.pde;

import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.IPackageFragment;
import org.eclipse.jdt.core.IPackageFragmentRoot;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.ISelectionService;
import org.eclipse.ui.internal.Workbench;

import com.ahmedmisbah.andgenplus.codegenerator.exceptions.CodeGeneratorException;
import com.ahmedmisbah.andgenplus.utils.file.FileUtil;
import com.ahmedmisbah.andgenplus.utils.velocity.VelocityTemplate;
import com.ahmedmisbah.andgenplus.utils.velocity.VelocityUtil;

public class PDEUtil {

	public static IProject getEclipseProject() {

		IProject ret = null;

		@SuppressWarnings("restriction")
		ISelectionService selectionService = Workbench.getInstance()
				.getActiveWorkbenchWindow().getSelectionService();

		ISelection selection = selectionService.getSelection();

		if (selection instanceof IStructuredSelection) {
			Object element = ((IStructuredSelection) selection)
					.getFirstElement();

			if (element instanceof IResource) {
				IResource res = (IResource) element;

				ret = res.getProject();
				/*
				 * System.out.println("Project location Path="+project.getLocation
				 * ());
				 * System.out.println("Project full Path="+project.getFullPath
				 * ());
				 * System.out.println("Project Raw Path="+project.getRawLocation
				 * ()); System.out.println("Project relative Path="+project.
				 * getProjectRelativePath());
				 */

			}
		}

		return ret;
	}

	public static String getSrcFolderPath() {
		return getEclipseProject().getLocation().toString()
				+ File.separator + "src" + File.separator;
	}

	public static String findClassPackage(String className, String extension)
			throws CoreException {

		String ret = null;

		IProject project = getEclipseProject();

		if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
			IJavaProject javaProject = JavaCore.create(project);
			IPackageFragment[] packages = javaProject.getPackageFragments();
			for (IPackageFragment mypackage : packages) {
				if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
					System.out.println("Package " + mypackage.getElementName());
					for (ICompilationUnit unit : mypackage
							.getCompilationUnits()) {
						if (unit.getElementName().equals(className + extension)) {
							ret = mypackage.getElementName() + "." + className;
							break;
						}

					}

					if (ret != null) {
						break;
					}
				}

			}
		}

		return ret;
	}
	
	public static ICompilationUnit findClassByName(String className, String extension)
			throws CoreException {

		ICompilationUnit ret = null;

		IProject project = getEclipseProject();

		if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
			IJavaProject javaProject = JavaCore.create(project);
			IPackageFragment[] packages = javaProject.getPackageFragments();
			for (IPackageFragment mypackage : packages) {
				if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
					System.out.println("Package " + mypackage.getElementName());
					for (ICompilationUnit unit : mypackage
							.getCompilationUnits()) {
						if (unit.getElementName().equals(className + extension)) {
							ret = unit;
							break;
						}

					}

					if (ret != null) {
						break;
					}
				}

			}
		}

		return ret;
	}

	/**
	 * 
	 * @param packageName
	 * @param isNewList
	 * @return
	 * @throws CoreException
	 */
	public static ICompilationUnit[] getPackageClasses(String packageName)
			throws CoreException {

		ICompilationUnit[] classList = null;

		IProject project = getEclipseProject();

		if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
			IJavaProject javaProject = JavaCore.create(project);
			IPackageFragment[] packages = javaProject.getPackageFragments();
			for (IPackageFragment mypackage : packages) {
				if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
					System.out.println("Package " + mypackage.getElementName());
					if (packageName != null
							&& mypackage.getElementName().equals(packageName)) {
						classList = mypackage.getCompilationUnits();
					}

				}

			}
		}

		return classList;
	}

	private static void printProjectInfo(IProject project)
			throws CoreException, JavaModelException {
		System.out.println("Working in project " + project.getName());
		// Check if we have a Java project
		if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")) {
			IJavaProject javaProject = JavaCore.create(project);
			printPackageInfos(javaProject);
		}
	}

	private static void printPackageInfos(IJavaProject javaProject)
			throws JavaModelException {
		IPackageFragment[] packages = javaProject.getPackageFragments();
		for (IPackageFragment mypackage : packages) {
			// Package fragments include all packages in the
			// classpath
			// We will only look at the package from the source
			// folder
			// K_BINARY would include also included JARS, e.g.
			// rt.jar
			if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
				System.out.println("Package " + mypackage.getElementName());
				printICompilationUnitInfo(mypackage);

			}

		}
	}

	private static void printICompilationUnitInfo(IPackageFragment mypackage)
			throws JavaModelException {
		for (ICompilationUnit unit : mypackage.getCompilationUnits()) {
			printCompilationUnitDetails(unit);

		}
	}

	public static void printIMethods(ICompilationUnit unit)
			throws JavaModelException {
		IType[] allTypes = unit.getAllTypes();
		for (IType type : allTypes) {
			printIMethodDetails(type);
		}
	}

	private static void printCompilationUnitDetails(ICompilationUnit unit)
			throws JavaModelException {
		System.out.println("Source file " + unit.getElementName());
		Document doc = new Document(unit.getSource());
		System.out.println("Has number of lines: " + doc.getNumberOfLines());
		printIMethods(unit);
	}

	private static void printIMethodDetails(IType type)
			throws JavaModelException {
		IMethod[] methods = type.getMethods();
		for (IMethod method : methods) {

			System.out.println("Method name " + method.getElementName());
			System.out.println("Signature " + method.getSignature());
			System.out.println("Return Type " + method.getReturnType());

		}
	}
	
	public static List<IMethod> getIMethods(ICompilationUnit unit)
			throws JavaModelException {
		
		List<IMethod> methods=new ArrayList<IMethod>();
		
		IType[] allTypes = unit.getAllTypes();
		for (IType type : allTypes) {
			methods.addAll(Arrays.asList(type.getMethods()));	
		}
		
		return methods;
	}
	
	
	public static void refreshProject()
			throws CoreException {
		
			// Refresh the project after generating all files
			getEclipseProject().refreshLocal(IResource.DEPTH_INFINITE, null);
			
	}
	
	public static String getClassPath(String packageName, String className) {
		String classPath = packageName + "." + className;
		System.out.println(classPath);

		return classPath;
	}

	public static String getFullClassPath(String sourcePath, String packageName,
			String className) {
		String classPath = sourcePath + packageName.replaceAll("\\.", "/")
				+ File.separator + className + ".java";
		System.out.println(classPath);

		return classPath;
	}

	public static void generateClass(String sourcePath, String packageName,
			String className, VelocityTemplate template)
			throws CodeGeneratorException {

		try {
			String classContent = VelocityUtil.buildTemplate(template);

			String classPath = getFullClassPath(sourcePath, packageName,
					className);

			FileUtil.writeFileAsUTF8(classContent, classPath);

		} catch (Exception e) {
			throw new CodeGeneratorException(e);
		}

	}

	public static void generateClass(String sourcePath, String packageName,
			String className, String classContent)
			throws CodeGeneratorException {

		try {

			String classPath = getFullClassPath(sourcePath, packageName,
					className);

			FileUtil.writeFileAsUTF8(classContent, classPath);

		} catch (Exception e) {
			throw new CodeGeneratorException(e);
		}

	}

	

	public static void addSingleLibraryToProject(File jarFile)
			throws CodeGeneratorException {
		
		try {

			IJavaProject javaProject = (IJavaProject) PDEUtil.getEclipseProject()
					.getNature(JavaCore.NATURE_ID);
			IClasspathEntry[] rawClasspath = javaProject
					.getRawClasspath();
			List<IClasspathEntry> list = new ArrayList<IClasspathEntry>(
					Arrays.asList(rawClasspath));

			String jarPath = jarFile.getAbsolutePath();
			boolean isAlreadyAdded = false;

			for (IClasspathEntry cpe : rawClasspath) {
				isAlreadyAdded = cpe.getPath().toOSString()
						.equals(jarPath);
				if (isAlreadyAdded) {
					break;
				}
			}

			if (!isAlreadyAdded) {
				IClasspathEntry jarEntry = JavaCore.newLibraryEntry(
						new Path(jarPath), null, null);
				list.add(jarEntry);
			}

			IClasspathEntry[] newClasspath = (IClasspathEntry[]) list
					.toArray(new IClasspathEntry[0]);
			javaProject.setRawClasspath(newClasspath, null);
		} catch (CoreException e) {
			throw new CodeGeneratorException(e);
		}
		/*try {
			InputStream is = new BufferedInputStream(new FileInputStream(
					jarFile.getAbsolutePath()));

			IFile file = GlobalConstants.project.getFile(jarFile.getName());
			file.create(is, false, null);

			IPath path = file.getFullPath();
			List<IClasspathEntry> libraries = new ArrayList<IClasspathEntry>();
			libraries.add(JavaCore.newLibraryEntry(path, null, null));

			IJavaProject javaProject = (IJavaProject) GlobalConstants.project
					.getNature(JavaCore.NATURE_ID);
			javaProject.setRawClasspath(
					libraries.toArray(new IClasspathEntry[libraries.size()]),
					null);

			is.close();

		} catch (JavaModelException e) {
			e.printStackTrace();
			// throw new CodeGeneratorException(e);
		} catch (FileNotFoundException e) {
			e.printStackTrace();
			// throw new CodeGeneratorException(e);
		} catch (CoreException e) {
			e.printStackTrace();
			// throw new CodeGeneratorException(e);
		} catch (IOException e) {
			e.printStackTrace();
			// throw new CodeGeneratorException(e);
		}*/
	}

	public static void addLibrariesToProject(File source)
			throws CodeGeneratorException {

		if (source.isDirectory()) {
			for (File jarFile : source.listFiles()) {
				addSingleLibraryToProject(jarFile);
			}

		} else {
			addSingleLibraryToProject(source);
		}

	}

}
